package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var client *mongo.Client
var db *mongo.Database
var users *mongo.Collection

func init() {
	url := "mongodb://admin:123456@127.0.0.1:27017"
	opts := options.Client()
	opts.ApplyURI(url).SetConnectTimeout(5 * time.Second)
	var err error
	client, err = mongo.Connect(context.TODO(), opts) // context.TODO()
	if err != nil {
		log.Fatal(err)
	}
	err = client.Ping(context.TODO(), nil)

	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 不能用:=
	db = client.Database("blog")
	users = db.Collection("users")
}

type User struct {
	ID   primitive.ObjectID `bson:"_id,omitempty"`
	Name string
	Age  int
}

func (u User) String() string {
	return fmt.Sprintf("<%s: %s,%d>", u.ID, u.Name, u.Age)
}

func main() {
	defer func() {
		if err := client.Disconnect(context.TODO()); err != nil {
			log.Fatal(err)
		}
	}()
	//fmt.Println(users)
	//insertOne()
	//insertMany()
	//findOne()
	//findMany1()
	//findMany2()
	//updateOne()
	updateMany()
}

func updateMany() {
	filter := bson.M{"age": bson.M{"$exists": true}} // 所有有age字段的文档
	update := bson.M{"$set": bson.M{"gender": "M"}}  // 为符合条件的文档设置
	users.UpdateMany(context.TODO(), filter, update)
}

func updateOne() {
	filter := bson.M{"age": bson.M{"$exists": true}, "name": "keke"} // 所有有age字段的文档
	update := bson.M{"$inc": bson.M{"age": -5}}                      // age字段减5
	ur, err := users.UpdateOne(context.TODO(), filter, update)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(ur.MatchedCount, ur.ModifiedCount)
}

func findMany2() {
	filter := bson.M{} // 无条件，全部符合
	var results []*User
	opt := options.Find()
	opt.SetSort(bson.M{"age": -1})
	//opt.SetProjection(bson.M{"age": false}) //age字段不投影，

	cursor, err := users.Find(context.TODO(), filter, opt)
	if err != nil {
		log.Fatal(err)
	}
	err = cursor.All(context.TODO(), &results)
	if err != nil {
		log.Fatal(err)
	}
	cursor.Close(context.TODO()) // 关闭游标
	for i, r := range results {
		fmt.Println(i, r)
	}
}

func findMany1() {
	filter := bson.M{} // 无条件，全部符合
	cursor, err := users.Find(context.TODO(), filter)
	if err != nil {
		log.Fatal(err)
	}
	var results []*User
	for cursor.Next(context.TODO()) {
		var u User
		err = cursor.Decode(&u)
		if err != nil {
			log.Fatal(err)
		}
		results = append(results, &u) // 装入容器
	}
	if err := cursor.Err(); err != nil {
		log.Fatal(err)
	}
	cursor.Close(context.TODO()) // 关闭游标
	fmt.Println(results)
}

func findOne() {
	//filter := bson.D{{"name", "jerry"}, {"age", 20}}
	//filter := bson.D{{"name", bson.D{{"$eq", "jerry"}}}}
	filter := bson.M{"name": bson.M{"$eq": "jerry"}}
	var u User
	err := users.FindOne(context.TODO(), filter).Decode(&u)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			// 说明没有任何匹配文档
			log.Println("没有匹配的文档")
			return
		}
		log.Fatal(err)
	}
	fmt.Println(u)

}

func insertMany() {
	jerry := User{Name: "jerry", Age: 20}
	ke := User{Name: "keke", Age: 20}

	insertResult, err := users.InsertMany(context.TODO(), []interface{}{ke, jerry})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(insertResult.InsertedIDs...)

}

func insertOne() {
	tom := User{Name: "tome", Age: 18}

	insertResult, err := users.InsertOne(context.TODO(), tom)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(insertResult.InsertedID)

}
